package org.jsola.hr.service.impl;

import org.jsola.admin.entity.DictItemDO;
import org.jsola.cache.ICache;
import org.jsola.common.PageKit;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.CacheKeyKit;
import org.jsola.hr.common.DateUtils;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.QdSocWebSite;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IZtcConfigDAO;
import org.jsola.hr.dto.SocAccountDTO;
import org.jsola.hr.dto.ZtcConfigAddDTO;
import org.jsola.hr.dto.ZtcConfigUpdateDTO;
import org.jsola.hr.dto.syncSocDTO.QdAttritionCheckDTO;
import org.jsola.hr.dto.syncSocDTO.QdEmploymentRegistrationUnit;
import org.jsola.hr.dto.syncSocDTO.QdIncrementCheckDTO;
import org.jsola.hr.dto.syncSocDTO.ZtcAccessTokenDTO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.EmpSocPlanDO;
import org.jsola.hr.entity.ZtcConfigDO;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.query.ZtcConfigQuery;
import org.jsola.hr.service.IEmpInfoService;
import org.jsola.hr.service.IEmpSocPlanService;
import org.jsola.hr.service.IZtcConfigService;
import org.jsola.hr.vo.ZtcConfigListVO;
import org.jsola.hr.vo.ZtcConfigVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 政企直通车配置
 *
 * @author zhr
 */
@Service("hrZtcConfigServiceImpl")
public class ZtcConfigServiceImpl implements IZtcConfigService {

    @Autowired
    private IZtcConfigDAO ztcConfigDAO;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private IEmpSocPlanService empSocPlanService;

    @Autowired
    private IAdminProviderService adminProviderService;

    @Autowired
    private ICache cache;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public ZtcConfigVO save(ZtcConfigAddDTO ztcConfigAddDTO, TokenUser tokenUser) {
        // 因为有可能是控制台添加的配置   tokenUser的siteId和要添加的租户Id可能不一样,这样跟租户查询的时候就可能出问题
        // 所以需要判断一下,如果tokenUser的siteId和要添加的租户Id如果不一样把tokenUser的siteId赋值成要添加的租户Id
        if (!tokenUser.getSiteId().equals(ztcConfigAddDTO.getAddSiteId())) {
            tokenUser.setSiteId(ztcConfigAddDTO.getAddSiteId());
        }
        if (checkRepeatCompany(ztcConfigAddDTO.getRelevancyCompanyId(), null)) {
            throw new ParamException("同一用工单位不可出现在两条配置中");
        }
        // 转DO
        ZtcConfigDO ztcConfigDO = ztcConfigAddDTO.to(ZtcConfigDO.class);
        // 保存
        ztcConfigDO = save(ztcConfigDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return ztcConfigDO.to(ZtcConfigVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(ZtcConfigUpdateDTO ztcConfigUpdateDTO, TokenUser tokenUser) {
        if (!tokenUser.getSiteId().equals(ztcConfigUpdateDTO.getAddSiteId())) {
            tokenUser.setSiteId(ztcConfigUpdateDTO.getAddSiteId());
        }
        if (checkRepeatCompany(ztcConfigUpdateDTO.getRelevancyCompanyId(), ztcConfigUpdateDTO.getId())) {
            throw new ParamException("同一用工单位不可出现在两条配置中");
        }
        //转DO
        ZtcConfigDO ztcConfigDO = ztcConfigUpdateDTO.to(ZtcConfigDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(ztcConfigDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... ztcConfigIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) ztcConfigIds);
    }


    @Override
    public ZtcConfigVO selectById(String ztcConfigId, String siteId) {
        ZtcConfigDO ztcConfigDO = selectDOById(ztcConfigId, siteId);
        if (ztcConfigDO == null) {
            return null;
        }
        return ztcConfigDO.to(ZtcConfigVO.class);
    }

    @Override
    public List<ZtcConfigListVO> select(ZtcConfigQuery ztcConfigQuery, String siteId) {
        List<ZtcConfigDO> ztcConfigDOList = selectDO(ztcConfigQuery, siteId);
        if (CollectionUtils.isEmpty(ztcConfigDOList)) {
            return ztcConfigDOList == null ? null : new ArrayList<>();
        }
        return ztcConfigDOList.stream()
                .map(ztcConfigDO -> ztcConfigDO.to(ZtcConfigListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(ZtcConfigQuery ztcConfigQuery, String siteId) {
        Example example = buildExample(ztcConfigQuery, siteId);
        return ztcConfigDAO.selectCountByExample(example);
    }

    @Override
    public Page<ZtcConfigListVO> selectPage(ZtcConfigQuery ztcConfigQuery, String siteId) {
        Example example = buildExample(ztcConfigQuery, siteId);
        Page<ZtcConfigDO> page = ztcConfigDAO.selectPageByExample(example,
                ztcConfigQuery.getPageNo(),
                ztcConfigQuery.getPageSize());

        return page.to(ZtcConfigListVO.class);
    }

    @Override
    public ZtcConfigDO selectDOById(String ztcConfigId, String siteId) {
        return listById(ztcConfigId, siteId);
    }

    @Override
    public List<ZtcConfigDO> selectDO(ZtcConfigQuery ztcConfigQuery, String siteId) {
        Example example = buildExample(ztcConfigQuery, siteId);
        return ztcConfigDAO.selectByExample(example);
    }

    @Override
    public Page<ZtcConfigListVO> selectPageConfig(ZtcConfigQuery ztcConfigQuery, TokenUser tokenUser) {
        List<ZtcConfigListVO> ztcConfigList;
        if (ztcConfigQuery.getConsole()) {
            ztcConfigList = ztcConfigDAO.selectConfig(ztcConfigQuery, null);
        } else {
            ztcConfigList = ztcConfigDAO.selectConfig(ztcConfigQuery, tokenUser.getSiteId());
        }
        if (CollectionUtils.isEmpty(ztcConfigList)) {
            return new Page<>(ztcConfigQuery.getPageSize(), ztcConfigQuery.getPageNo());
        }
        return PageKit.startPage(ztcConfigList, ztcConfigQuery.getPageNo(), ztcConfigQuery.getPageSize());
    }

    @Override
    public boolean ztcAccessTokenExist(String companyId) {
        ZtcConfigDO ztcConfigDO = selectByCompanyId(companyId);
        if (ObjectUtils.isEmpty(ztcConfigDO)) {
            throw new ParamException("本用工单位还未配置直通车相关参数,请配置后再进行增员");
        }
        // 获取这个用工单位的appId
        String accessTokenKey = CacheKeyKit.getAccessTokenByAppId(ztcConfigDO.getAppId());
        String accessToken = cache.get(accessTokenKey);
        return !StringUtils.isEmpty(accessToken);
    }

    @Override
    public void saveCacheAccessToken(ZtcAccessTokenDTO ztcAccessTokenDTO) {
        ZtcConfigDO ztcConfigDO = selectByCompanyId(ztcAccessTokenDTO.getCompanyId());
        // 获取这个账号的accessToken
        String accessTokenKey = CacheKeyKit.getAccessTokenByAppId(ztcConfigDO.getAppId());
        String accessToken = QdSocWebSite.getAccessToken(ztcConfigDO, ztcAccessTokenDTO.getUserName(),
                ztcAccessTokenDTO.getPassword());
        cache.set(accessTokenKey, accessToken, DateUtils.getRemainMillisecondOneDay(new Date()));
    }

    @Override
    public ZtcConfigDO selectByCompanyId(String companyId) {
        Example example = new Example(ZtcConfigDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andLike("relevancyCompanyId", "%" + companyId + "%");
        return ztcConfigDAO.selectOneByExample(example);
    }

    @Override
    public List<QdIncrementCheckDTO> checkEmpQdWebSite(ZtcAccessTokenDTO ztcAccessTokenDTO, TokenUser tokenUser) {
        List<QdIncrementCheckDTO> result = new ArrayList<>();
        List<String> planIdList = ztcAccessTokenDTO.getPlanIdList();
        ParamException.notEmpty(planIdList, "请选择增员员工");
        List<EmpSocPlanDO> empSocPlanList = empSocPlanService.selectByIdList(planIdList, tokenUser.getSiteId());
        Map<String, EmpSocPlanDO> planMap = empSocPlanList.stream()
                .collect(Collectors.toMap(EmpSocPlanDO::getEmpId, v -> v));
        List<String> empIdList = empSocPlanList.stream().map(EmpSocPlanDO::getEmpId).collect(Collectors.toList());
        // 写死青岛
        SocAccountDTO socAccountDTO = cache.get(CacheKeyKit.getSocAccount(tokenUser.getUserId(), "283"));
        if(ObjectUtils.isEmpty(socAccountDTO)){
            throw new ParamException("登陆已超时或未登录,请重新登录社保网站");
        }
        List<EmpInfoDO> empInfoList = empInfoService.selectDoByIds(empIdList);
        for (EmpInfoDO empInfoDO : empInfoList) {
            QdIncrementCheckDTO checkDTO = QdSocWebSite.
                    checkIncrementEmp(empInfoDO.getIdCard(), socAccountDTO.getCookie());
            checkDTO.setEmpId(empInfoDO.getId());
            EmpSocPlanDO empSocPlanDO = planMap.get(empInfoDO.getId());
            checkDTO.setPlanId(empSocPlanDO.getId());
            checkDTO.setXm(empInfoDO.getName());
            checkDTO.setSfzhm(empInfoDO.getIdCard());
            checkDTO.setEmpId(empInfoDO.getId());
            // 如果有区级代码就把对应的省和市都找到
            String district = checkDTO.getHkszdxzqh();
            if (!StringUtils.isEmpty(district)) {
                // 市级代码
                String city = district.substring(0, 4) + "00";
                checkDTO.setCity(city);
                // 省级代码
                String province = district.substring(0, 2) + "0000";
                checkDTO.setProvince(province);
                DictItemDO provinceAddress = adminProviderService.selectByCodeAndKey("1206", province);
                DictItemDO cityAddress = adminProviderService.selectByCodeAndKey("1206", city);
                DictItemDO districtAddress = adminProviderService.selectByCodeAndKey("1206", district);
                // 根据省市区代码找到户籍地址
                checkDTO.setAddressHousehold(provinceAddress.getDictItemValue() +
                        cityAddress.getDictItemValue() + districtAddress.getDictItemValue());
            }
            result.add(checkDTO);
        }
        return result;
    }

    @Override
    public List<QdAttritionCheckDTO> checkDecreaseEmpQdWebSite(ZtcAccessTokenDTO ztcAccessTokenDTO, TokenUser tokenUser) {
        List<QdAttritionCheckDTO> result = new ArrayList<>();
        List<String> planIdList = ztcAccessTokenDTO.getPlanIdList();
        ParamException.notEmpty(planIdList, "请选择增员员工");
        List<EmpSocPlanDO> empSocPlanList = empSocPlanService.selectByIdList(planIdList, tokenUser.getSiteId());
        Map<String, EmpSocPlanDO> planMap = empSocPlanList.stream()
                .collect(Collectors.toMap(EmpSocPlanDO::getEmpId, v -> v));
        List<String> empIdList = empSocPlanList.stream().map(EmpSocPlanDO::getEmpId).collect(Collectors.toList());
        // 暂时写死青岛
        SocAccountDTO socAccountDTO = cache.get(CacheKeyKit.getSocAccount(tokenUser.getUserId(), "283"));
        if(ObjectUtils.isEmpty(socAccountDTO)){
            throw new ParamException("登陆已超时或未登录,请重新登录社保网站");
        }
        List<EmpInfoDO> empInfoList = empInfoService.selectDoByIds(empIdList);
        for (EmpInfoDO empInfoDO : empInfoList) {
            QdAttritionCheckDTO checkDTO =
                    QdSocWebSite.checkAttritionEmp(empInfoDO.getIdCard(), socAccountDTO.getCookie());
            checkDTO.setEmpId(empInfoDO.getId());
            EmpSocPlanDO empSocPlanDO = planMap.get(empInfoDO.getId());
            checkDTO.setPlanId(empSocPlanDO.getId());
            checkDTO.setEmpId(empInfoDO.getId());
            result.add(checkDTO);
        }
        return result;
    }

    @Override
    public List<QdEmploymentRegistrationUnit> getEmploymentRegistrationUnit(TokenUser tokenUser, String areaId) {
        SocAccountDTO socAccountDTO = cache
                .get(CacheKeyKit.getSocAccount(tokenUser.getUserId(), areaId));
        return QdSocWebSite.getEmploymentRegistrationUnit(socAccountDTO.getCookie());
    }

    @Override
    public int deleteById(String id) {
        Example example = new Example(ZtcConfigDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("id", id);
        return ztcConfigDAO.deleteByExample(example);
    }

    @Override
    public String getWebSiteCookie(String areaId, TokenUser tokenUser) {
        SocAccountDTO socAccountDTO = cache
                .get(CacheKeyKit.getSocAccount(tokenUser.getUserId(), areaId));
        if(ObjectUtils.isEmpty(socAccountDTO)){
            throw new ParamException("当前账号未登录社保网站");
        }
        return socAccountDTO.getCookie();
    }

    /**
     * 校验同一用工单位不可出现两条配置里 (返回true说明有重复数据)
     */
    private boolean checkRepeatCompany(String companyIds, String updateId) {
        String[] companyIdArray = companyIds.split(",");
        List<String> companyIdList = Arrays.asList(companyIdArray);
        if (CollectionUtils.isEmpty(companyIdList)) {
            return false;
        }
        Example example = new Example(ZtcConfigDO.class);
        example.and()
                .andEqualTo("valid", true);
        for (String companyId : companyIdList) {
            example.and().andLike("relevancyCompanyId", "%" + companyId + "%");
        }
        List<ZtcConfigDO> ztcConfigList = ztcConfigDAO.selectByExample(example);
        if (!StringUtils.isEmpty(updateId)) {
            ztcConfigList = ztcConfigList.stream().
                    filter(ztcConfig -> !updateId.equals(ztcConfig.getId())).collect(Collectors.toList());
        }
        return !CollectionUtils.isEmpty(ztcConfigList);
    }

    /**
     * 根据查询参数，构建example
     *
     * @param ztcConfigQuery 查询参数
     * @param siteId         所属站点id
     * @return example
     */
    private Example buildExample(ZtcConfigQuery ztcConfigQuery, String siteId) {
        Example example = new Example(ZtcConfigDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        // 排序
        ExampleKit.setExampleOrder(example, ztcConfigQuery.getOrders());
        return example;
    }
}




